class addr_range;
    // class properties
    bit [31:0] start_addr;
    bit [31:0] end_addr  ;

    // constructor
    function new();    
        start_addr = 10;
        end_addr   = 50;
    endfunction

    // copy method
    function addr_range copy();
        addr_range inst = new();
        inst.start_addr = this.start_addr;
        inst.end_addr   = this.end_addr;
        return inst;
    endfunction
endclass

class packet;
    // class properties
    bit [31:0] addr;
    bit [31:0] data;
    addr_range ar; // class handle

    // constructor
    function new();
        addr    = 32'h10;
        data    = 32'hFF;
        ar      = new(); // creating object
    endfunction

    // copy method
    function packet copy();
        packet inst = new();
        inst.addr = this.addr;
        inst.data = this.data;
        inst.ar   = this.ar.copy(); // copying object
        return inst;
    endfunction

    // method to display class properties
    function void display();
        $display("---------------------------------------------------------");
        $display("\t addr       = %0h",addr);
        $display("\t data       = %0h",data);
        $display("\t start_addr = %0d",ar.start_addr);
        $display("\t end_addr   = %0d",ar.end_addr);
        $display("---------------------------------------------------------");
    endfunction
endclass

// -- module ---
module class_copy;
    packet pkt_1;
    packet pkt_2;

    initial begin
        $display("======================[Shallow Copy]======================");
        pkt_1 = new();   // Creating pkt_1 object
        $display("****  Call pkt_1.display()  ****");
        pkt_1.display();

        pkt_2 = new pkt_1;   // [Shallow Copy] Creating pkt_2 object and copying pkt_1 to pkt_2 
        $display("****  Call pkt_2.display()  ****");
        pkt_2.display();

        // Changing values with pkt_2 handle
        pkt_2.addr = 32'h68;
        pkt_2.ar.start_addr = 60;
        pkt_2.ar.end_addr = 80;
        $display("Changing pkt_2 properties: addr = 0x68, ar.start_addr = 60, ar.end_addr = 80");

        // Changes made to pkt_2.ar properties reflected on pkt_1.ar, so only handle of the object get copied, this is called shallow copy
        $display("****  Call pkt_1.display() after changing pkt_2 properties ****");
        pkt_1.display();
        $display("****  Call pkt_2.display() after changing pkt_2 properties ****");
        pkt_2.display();
        $display("======================[Shallow Copy]======================");



        $display("=======================[Deep Copy]=======================");
        pkt_1 = new();   // Creating pkt_1 object
        $display("****  Call pkt_1 display  ****");
        pkt_1.display();

        pkt_2 = pkt_1.copy(); // [Deep Copy] Calling copy method
        $display("****  Call pkt_2 display  ****");
        pkt_2.display();

        // Changing values with pkt_2 handle
        $display("Changing pkt_2 properties: addr = 0x68, ar.start_addr = 60, ar.end_addr = 80");
        pkt_2.addr = 32'h68;
        pkt_2.ar.start_addr = 60;
        pkt_2.ar.end_addr = 80;

        $display("****  Call pkt_1 display after changing pkt_2 properties ****");
        pkt_1.display();
        $display("****  Call pkt_2 display after changing pkt_2 properties ****");
        pkt_2.display();
        $display("=======================[Deep Copy]=======================");
    end
endmodule